/** @file    Object.cpp
 *  @author  Alessandro Polo
 *  @version $Id: Object.cpp 2831 2010-08-02 22:15:14Z alex $
 *  @brief
 * File containing methods for the wosh::Object class.
 * The header for this class can be found in Object.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/Object.h>
 #include <core/ObjectAllocator.h>
 #include <core/DataModels.h>
 #include <core/Utilities.h>


using namespace std;
namespace wosh {

 WOSH_REGISTER(wosh::Object, "wosh::ISerializable", 1.01, _static_Object)

void object_assign( Object* object, const std::string& entity_id ) {
	if ( object == NULL ) return;
	object->objEntityID = entity_id;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

Object::Object( const Object& m )
	: objEntityID(m.objEntityID), objName(m.objName),
	objPermission(m.objPermission), objURI(m.objURI),
	objParent(m.objParent) {
 }

Object::Object( const Object* parent ) {
	this->objParent = NULL;
	Utilities::UUID( this->objEntityID );

	this->objName = "";
	this->objPermission.setMask(Permission::RW, Permission::Read, Permission::Read);

	Object::setParentObject(parent);
 }

Object::Object( const Object* parent, const string& name ) {
	this->objParent = NULL;
	Utilities::UUID( this->objEntityID );

	this->objName = name;
	this->objPermission.setMask(Permission::RW, Permission::Read, Permission::Read);

	Object::setParentObject(parent);
 }

Object::Object( const Object* parent, const std::string& name, const URI& uri, const Permission& permission ) {
	this->objParent = NULL;
	Utilities::UUID( this->objEntityID );

	this->objName = name;
	this->objURI = uri;
	this->objPermission = permission;

	Object::setParentObject(parent);
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Object::setName( const std::string& value ) {
	this->objName = value;
	if ( this->objURI.getName().empty() )
		this->objURI.setName( value );
 }

void Object::setName( const std::string& basename, long id ) {
	Object::setName( Utilities::format("%s#%ld", basename.c_str(), id) );
 }

void Object::setParentObject( const Object* parent ) {
	if ( this->objParent == NULL && parent != NULL ) { // setting parent first time
		// so inherit permissions and ownership?
		this->objPermission.inherit( parent->objPermission, Permission::Overwrite_All, true );

		// so inherit URI?
		if ( this->objURI.isKernelEmpty() )
			this->objURI.setKernelName( parent->objURI.getKernelName() );
		if ( !this->objURI.isPathEmpty() ) {
			this->objURI.setParent( parent->objURI );
		 }

	 }
	this->objParent = parent;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Object& Object::operator=( const Object& m ) {
	if (this == &m) return *this; // same object?
	this->objEntityID = m.objEntityID;
	this->objName = m.objName;
	this->objPermission = m.objPermission;
	this->objURI = m.objURI;
	this->objParent = m.objParent;
	return *this;
 }

bool Object::operator==( const Object &other ) const {
	if ( this->objName != other.objName ) return false;
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool Object::updateHash( DataHashContext* hash_context ) const {
	if ( hash_context == NULL ) return false;
	bool ret = true;
	ret = hash_context->update( this->objEntityID ) & ret;
	ret = hash_context->update( this->objName ) & ret;
	ret = this->objPermission.updateHash(hash_context) & ret;
	ret = this->objURI.updateHash(hash_context) & ret;
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER(wosh::ObjectTypeInfo, "wosh::ISerializable", 1.01, _static_ObjectTypeInfo)

ObjectTypeInfo& ObjectTypeInfo::operator=(const ObjectTypeInfo& m) {
	if (this == &m) return *this; // same object?
	this->name = m.name;
	this->version = m.version;
	this->parent = m.parent;
	this->allocable = m.allocable;
	return *this;
 }
bool ObjectTypeInfo::operator==(const ObjectTypeInfo &other) const {
	if ( this->name != other.name ) return false;
	if ( this->version != other.version ) return false;
	if ( this->parent != other.parent ) return false;
	if ( this->allocable != other.allocable ) return false;
	return true;
 }

bool ObjectTypeInfo::operator>(const ObjectTypeInfo& other) const {
	if ( this->name > other.name ) return true;
	else return false;
	if ( this->version > other.version ) return true;
	else return false;
	if ( this->allocable == true && other.allocable != false ) return true;
	else return false;
	//if ( this->parent > other.parent ) return true;
	return true;
 }

bool ObjectTypeInfo::operator<(const ObjectTypeInfo& other) const {
	if ( this->name < other.name ) return true;
	else return false;
	if ( this->version < other.version ) return true;
	else return false;
	if ( this->allocable == false && other.allocable != true ) return true;
	else return false;
	//if ( this->parent < other.parent ) return true;
	return false;
 }

std::string ObjectTypeInfo::toString() const {
	return Utilities::format("%s [%g,%d] (%s)", this->name.c_str(), this->version, this->allocable, this->parent.c_str() );
 }

bool ObjectTypeInfo::updateHash( DataHashContext* hash_context ) const {
	if ( hash_context == NULL ) return false;
	bool ret = true;
	ret = hash_context->update( this->name ) & ret;
	ret = hash_context->update( this->version ) & ret;
	ret = hash_context->update( this->allocable ) & ret;
	return ret;
 }

DataFieldCollector<ObjectTypeInfo>* ObjectTypeInfo::getDataFields() {
	DataFieldCollector<ObjectTypeInfo>* fields = new DataFieldCollector<ObjectTypeInfo>();
	fields->add<const std::string&, Variant>(&ObjectTypeInfo::getName, "Name", 0);
	fields->add<double, Variant>(&ObjectTypeInfo::getVersion, "Version", 1);
	fields->add<const std::string&, Variant>(&ObjectTypeInfo::getParent, "Parent", 2);
	fields->add<bool,Variant>(&ObjectTypeInfo::isAllocable, "Allocable", 3);
	return fields;
 }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
